package org.xtremeobjects.domain.model.java5;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.xtremeobjects.anotations.Hidden;
import org.xtremeobjects.domain.model.Clazz;
import org.xtremeobjects.domain.model.ClazzRepository;
import org.xtremeobjects.domain.model.Property;

class PropertyJava5 implements Property {

	private Clazz clazz;

	public String name;

	private Method getter;

	private Method setter;

	private Field field;
	
	private ClazzRepository clazzRepository;

	PropertyJava5(Clazz clazz, String propertyName, Method getter, Method setter, ClazzRepository clazzRepository) {
		this.clazz = clazz;
		this.name = propertyName;
		this.getter = getter;
		this.setter = setter;
		this.field = findField(clazz.getImplementationClass(), propertyName);
		this.clazzRepository = clazzRepository;
	}

	private Field findField(Class<?> clazz, String propertyName) {
		Field field=null;
		try {
			field = clazz.getDeclaredField(propertyName);
		} catch (SecurityException e) {
		} catch (NoSuchFieldException e) {
			if(clazz.getSuperclass()!=null)
				field = findField(clazz.getSuperclass(), propertyName);
		}
		return field;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.xtremeobjects.domain.model.IProperty#getName()
	 */
	public String getName() {
		return name;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.xtremeobjects.domain.model.IProperty#getClazz()
	 */
	public Clazz getClazz() {
		return clazz;
	}

	public Clazz getType() {
		return clazzRepository.findOrCreateByClass(getter.getReturnType());
	}

	public Object getValue(Object obj) {
		Object ret = null;
		try {
			ret = getter.invoke(obj, (Object[])null);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return ret;
	}

	public boolean isReadOnly() {
		return setter == null;
	}

	public void setValue(Object obj, Object value) {
		if (setter == null)
			throw new RuntimeException("Cannot set value, property "
					+ getName() + " is read only");

		try {
			setter.invoke(obj, new Object[] { value });
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	public String getLabel() {
		org.xtremeobjects.anotations.Property annotation=null;
		if (field != null)
			annotation = (org.xtremeobjects.anotations.Property) field.getAnnotation(org.xtremeobjects.anotations.Property.class);
		else if(getter != null)
			annotation = (org.xtremeobjects.anotations.Property) getter.getAnnotation(org.xtremeobjects.anotations.Property.class);

		if (annotation != null)
			return annotation.name();
		return this.name;
	}

	public boolean isHidden() {
		if(field != null)
			return field.isAnnotationPresent(Hidden.class);
		if(getter != null)
			return getter.isAnnotationPresent(Hidden.class);
		return false;
	}
}
